﻿/// ****************************************************************************
/// Author:	        Robin Zhu
/// Create Date:	2012-4-17
/// Purpose: 		验证服务的数据库实现版本
/// ****************************************************************************
/// Modify By		Date			Remark
/// Robin           2012-4-26       通过UserSession的LastActivityDate判断是否过期
/// Robin           2013-8-27       当LastActivityDate为空时使用当前日期
/// Robin           2015-3-26       获取UserSession时判断用户是否能登录App
/// ****************************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Diagnostics;
using System.Net;

namespace RB.Web.Security.Rdb
{
    /// <summary>
    /// 验证服务的数据库实现版本
    /// </summary>
    public class DbAuthenticateService : IAuthenticateService
    {
        public UserSession GetSession(string appCode, string ticket, int userIsOnlineTimeWindow)
        {
            Debug.Print("DbAuthenticateService.GetSession ticket=" + ticket + " userIsOnlineTimeWindow=" + userIsOnlineTimeWindow.ToString());
            UserSessionSet sessionSet = new UserSessionSet();
            UserSession result = sessionSet[ticket];
            if (result != null && result.LogoutTime == null)
            {
                if (userIsOnlineTimeWindow <= 0
                    || (DateTime.Now - (result.LastActivityDate ?? DateTime.Now)).TotalMinutes < userIsOnlineTimeWindow)
                {
                    UserAccountSet accountSet = new UserAccountSet();
                    UserAccount user = accountSet.GetLogonUser(result.UserId, appCode);

                    if (user != null)
                    {
                        if (result.AppCode != appCode)
                        {
                            result.AppCode = appCode;
                        }

                        sessionSet.Update(p => new { LastActivityDate = DateTime.Now, AppCode = appCode },
                            p => p.Ticket == ticket);


                        accountSet.Update(p => new { LastActivityDate = DateTime.Now },
                            p => p.Id == result.UserId);

                        result.NickName = user.FirstName;

                        var roles = (new UserRoleSet()).GetByUser(appCode, result.UserId);
                        result.Roles = roles.Select(p => p.Code).ToArray();

                        var permCodes = (new RolePermissionSet()).GetPermCodesByRoles(roles.Select(p => p.Id).ToArray());
                        result.PermissionCodes = permCodes;

                        return result;
                    }
                }
                else
                {
                    SignOut(ticket);
                }
            }
            return null;
        }

        public void SignOut(string ticket)
        {
            UserSessionSet sessionSet = new UserSessionSet();
            sessionSet.Update(p => new { LogoutTime = DateTime.Now }, p => p.Ticket == ticket);
        }


        public UserSession CreateSession(string appCode, string username, string ipAddress, string httpForwarded)
        {
            // 检查是否可以登录指定应用

            UserAccountSet userAccountSet = new UserAccountSet();
            UserAccount account = userAccountSet.GetLogonUser(username, appCode);
            if (account != null)
            {
                UserSession result = new UserSession()
                {
                    AppCode = appCode,
                    UserId = account.Id,
                    UserName = account.UserName,
                    Ticket = GenerateTicket2(httpForwarded??ipAddress),
                    IPAddress = ipAddress,
                    HttpForwarded = httpForwarded,
                    LoginTime = DateTime.Now,
                    LastActivityDate = DateTime.Now,
                    IsStaff = account.IsStaff,
                    NickName = account.FirstName
                };
                UserSessionSet sessionSet = new UserSessionSet();
                sessionSet.Add(result);

                var roles = (new UserRoleSet()).GetByUser(appCode, account.Id);
                result.Roles = roles.Select(p => p.Code).ToArray();

                var permCodes = (new RolePermissionSet()).GetPermCodesByRoles(roles.Select(p => p.Id).ToArray());
                result.PermissionCodes = permCodes;

                return result;
            }
            return null;
        }

        private string GenerateTicket()
        {
            Guid guidTicket = Guid.NewGuid();

            return HttpServerUtility.UrlTokenEncode(guidTicket.ToByteArray());
        }

        private string GenerateTicket2(string ipString)
        {
            Guid guidTicket = Guid.NewGuid();
            var guidCodes = HttpServerUtility.UrlTokenEncode(guidTicket.ToByteArray());

            if (!string.IsNullOrWhiteSpace(ipString))
            {
                IPAddress ipAddress;
                if (IPAddress.TryParse(ipString, out ipAddress))
                {
                    byte[] ipBytes = ipAddress.GetAddressBytes();
                    var ipCodes = HttpServerUtility.UrlTokenEncode(ipBytes);

                    if (ipCodes.Length < guidCodes.Length)
                    {
                        guidCodes = ipCodes + guidCodes.Substring(0, guidCodes.Length - ipCodes.Length);
                    }
                }
            }
            return guidCodes;
        }

        public void LogPasswordAttemp(string appCode, string username, string password, string ipAddress, string httpForwarded)
        {
            try
            {
                UserAccountSet userAccountSet = new UserAccountSet();
                UserAccount account = userAccountSet.FirstOrDefault(t => t.UserName == username);

                var attemp = new UserPasswordAttempLog()
                {
                    AppCode = VarAuthorization.AppCode,
                    UserId = (account != null ? account.Id : Guid.Empty),
                    UserName = username,
                    Password = password,
                    LoginTime = DateTime.Now,
                    IPAddress = ipAddress,
                    HttpForworded = httpForwarded,
                    IsStaff = (account != null ? account.IsStaff : false)
                };

                (new UserPasswordAttempLogSet()).Add(attemp);
            }
            catch
            {
            }
        }
    }
}
